package fr.mywiki.business.versioning.diff;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import fr.mywiki.business.utils.StringUtils;
import fr.mywiki.business.versioning.VersionLite;

/**
 * Represents a set of VersionDiff objects, useful to write or read them.
 * Contains a set of versions inside a map which links a version id to
 * 
 * @author tlombard
 */
public class DiffFile {
	/** The identifier of the reference version */
	private Long refId;
	
	/** The content of the reference version */
	private String refText;
	
	/** The other versions : id <-> VersionDiff object */
	private HashMap versions;

	/** In the decompressed version file, each line starts with this string */
	private static final String STARTLINE_INDICATOR = "@";
	
	private DiffFile() {}
	
	/**
	 * Constructs the diff file object from a String representation
	 *  
	 * @param str a String representation of the diff file.
	 */
	public DiffFile(String str) {
		String[] versionTokens = str.split(STARTLINE_INDICATOR);
		
		versions = new HashMap();
		
		// Extract the first element, which contains the reference id and text
		String reference = versionTokens[1];
		
		// Extract the reference id
		int refSep = reference.indexOf("\n");
		refId = new Long(reference.substring(1,refSep));
		
		// Extract the reference text
		refText = reference.substring(refSep+1,reference.length()-1);
		
		versions.put(refId, refText);
		
		// Extract the other versions
		for (int i = 2; i < versionTokens.length; i++) {
			String token = versionTokens[i];
			
			refSep = reference.indexOf("\n");
			Long versionId = new Long(token.substring(1,refSep));
			
			String versionDiffText = token.substring(refSep);
			versionDiffText = versionDiffText.substring(1,
					versionDiffText.length() - 1); // remove "\n"
			VersionDiff vd = new VersionDiff(versionDiffText);
			
			versions.put(versionId,vd.getString(refText));
		}
	}
	
	public Map getVersions() {
		return versions;
	}
	
	/**
   * Replaces every occurrence of <code>STARTLINE_INDICATOR</code> in the
   * string given in parameter by
   * <code>STARTLINE_INDICATOR</code><code>STARTLINE_INDICATOR</code> and
   * returns the result.
   * 
   * @param str
   *          a String potentially containing "@"
   * @return a String not containing single "@".
   */
	private static String replaceCharStartLine(String str) {
		return str.replaceAll(DiffFile.STARTLINE_INDICATOR, DiffFile.STARTLINE_INDICATOR
				+ DiffFile.STARTLINE_INDICATOR);
	}
	
	/**
   * Builds the diff file containing all the versions given in parameter.
   * 
   * @param versionLites
   *          a List of <code>VersionLite</code> objects.
   * @param versionTexts
   *          a List of <code>String</code> objects.
   * @return a String object representing the list of versions
   */
	public static String buildDiffFile(List versionLites, List versionTexts) {
		StringBuffer buffer = new StringBuffer();

		// First, write the identifier of the first version lite
		VersionLite lite = (VersionLite) versionLites.get(0);
		String textRef = DiffFile.replaceCharStartLine((String) versionTexts.get(0));

		buffer.append(DiffFile.STARTLINE_INDICATOR + " "+ lite.getId().toString() + "\n");
		buffer.append(textRef + "\n");

		// Compute the number of versions to considerate
		int max = Math.min(versionLites.size(), versionTexts.size());
		for (int i = 1; i < max; i++) {
			buffer.append(DiffFile.STARTLINE_INDICATOR + " "
					+ ((VersionLite) versionLites.get(i)).getId().toString() + "\n");
			String text2 = replaceCharStartLine((String) versionTexts.get(i));
			
			Diff diff = new Diff(StringUtils.toStringArray(textRef), StringUtils
					.toStringArray(text2));
			VersionDiff diffObj = new VersionDiff(diff, text2);
			
			buffer.append(diffObj.diffObjToString() + "\n");
		}

		return buffer.toString();
	}
}
